/******************************************************************************
 * Student Name: Ofri Keidar
 * Exercise Name: Ex2
 * File Description: Class LecturerLinkedList's implementation
 ******************************************************************************/

#include "LecturerLinkedList.h"
#define INDEX_INIT_VAL 0 // used to initialize new nodes' index

//////////////////////////////////////////////////////////////////////////////////// class Node's methods

//////////////////////////////////////////////////////////////////// public methods

/***************************************************************************************
* function name: Node(Lecturer* const LecturerToPoint)
* The Input: Lecturer data to point at
* The output: None
* The Function operation: Initializes lecturer data pointer to point at given lecturer.
*						  Previous and next node pointers are initialized as NULL and
*						  index is initialized as INDEX_INIT_VAL because the new node's
*						  position in the linked list is not set yet
***************************************************************************************/
LecturerLinkedList::Node::Node(Lecturer* const LecturerToPoint): m_lecturerData(LecturerToPoint) {

	// new node is not yet linked to the list
	m_prevNode = NULL;
	m_nextNode = NULL;
	m_index = INDEX_INIT_VAL;
}

/****************************************************************************************
* function name: ~Node()
* The Input: None
* The output: None
* The Function operation: Deletes lecturer data being pointed by the node.
*			  			  Next and previous nodes are linked and the next nodes'
*			              indices are decremented
***************************************************************************************/
LecturerLinkedList::Node::~Node() {

	delete m_lecturerData; // delete allocated memory for pointed student

	// link next node and previous node
	if (m_nextNode != NULL) { // not end of list
		m_nextNode->m_prevNode = m_prevNode;
	}
	if (m_prevNode != NULL) { // not beginning of list
		m_prevNode->m_nextNode = m_nextNode;
	}

	// decrement next nodes' index
	Node* currentNode = m_nextNode;
	while (currentNode != NULL) { // scan list to its end
		--(currentNode->m_index); // decrement index
		currentNode = currentNode->m_nextNode; // move to next node
	}

}

//////////////////////////////////////////////////////////////////////////////////// class Node's methods

//////////////////////////////////////////////////////////////////// private methods

/***************************************************************************************
* function name: findPlace(const Lecturer& newLecturer)
* The Input: Pointer to lecturer to add
* The output: Node pointer to which the new lecturer should be linked.
* 	      If a lecturer with new lecturer's id already exists, NULL is returned
* The Function operation: Uses 2 node pointers- one to point at previous node being
*						  scanned and another one to point at current node on list.
*						  Method compares current lecturer's id with given lecturer's id.
*						  If id's are equal, given lecturer cannot be added and NULL is
*						  returned. If current lecturer's id is smaller than new lecturer's,
*						  a pointer to current node is returned
***************************************************************************************/
LecturerLinkedList::Node* LecturerLinkedList::findPlace(const Lecturer& newLecturer) const {

	Node* prev = m_headDummy; // pointer to previous node being scanned
	Node* curr = prev->m_nextNode; // pointer to current node being scanned

	while (prev->m_nextNode->m_lecturerData != NULL) {

		if (curr->m_lecturerData->getID() == newLecturer.getID()) {
			return NULL; //duplicate id found
		}

		if (newLecturer.getID() < curr->m_lecturerData->getID()) {
			return curr;
		}
		// move to next node
		prev = curr;
		curr = curr->m_nextNode;
	}

	return curr;
}

/***************************************************************************************
* function name: internalAdd(Lecturer* newLecturer, Node* before)
* The Input: Pointer to lecturer to be added and a pointer to the node where the new
* 	     lecturer will be linked
* The output: None
* The Function operation: A new node is created pointing to lecturer to be added.
*			  Method links the new node before the given node and then
*			  increments next nodes' indices
***************************************************************************************/
void LecturerLinkedList::internalAdd(Lecturer& newLecturer, Node* before) {

	Node* newNode = new Node(&newLecturer); // create a node pointing to new lecturer
	// link node to list
	Node* temp = before->m_prevNode;
	newNode->m_nextNode = before;
	before->m_prevNode = newNode;

	newNode->m_prevNode = temp;
	temp->m_nextNode = newNode;

	++(m_tailDummy->m_index); // increment tail's index
	// update new node's index
	if (before == m_tailDummy) {
		newNode->setIndex(m_tailDummy->m_index);
	} else {
		newNode->setIndex((before->m_index));
	}

	// increment index of next nodes
	while (before != m_tailDummy) {
		before->setIndex((before->m_index)+1);
		before = before->m_nextNode;
	}

}

//////////////////////////////////////////////////////////////////// public methods

/***************************************************************************************
* function name: LecturerLinkedList()
* The Input: None
* The output: None
* The Function operation: List's head and tail are pointers to nodes which do not point
*			              at lecturers (point NULL). This implementation prevents the
*			              need to check if previous/next nodes are NULL- makes code
*		                  more quickly because there are less conditions to check
***************************************************************************************/
LecturerLinkedList::LecturerLinkedList() {

	// create dummy nodes to avoid checking NULL values
	m_headDummy = new Node(NULL);
	m_tailDummy = new Node(NULL);

	m_headDummy->m_nextNode = m_tailDummy;
	m_tailDummy->m_prevNode = m_headDummy;
	m_currentNode = m_headDummy;
}

/***************************************************************************************
* function name: ~LecturerLinkedList()
* The Input: None
* The output: None
* The Function operation: Scans list from start to end and deletes each node
***************************************************************************************/
LecturerLinkedList::~LecturerLinkedList() {

	// scan list and delete nodes
	Node* currNode = m_headDummy;
	Node* prevNode = m_headDummy;

	while (currNode != NULL) {
		// move to next node on list and delete the previous which has been scanned
		currNode = currNode->m_nextNode;
		delete prevNode;
		prevNode = currNode;
	}
	delete prevNode; // delete last node on list
}

/***************************************************************************************
* function name: addNode(Lecturer* newLecturer)
* The Input: Pointer to student to be added
* The output: True if student was added, False is not
* The Function operation: If NULL was given as student pointer, it is not added and
*			              False is returned.
*			              Method calls findPlace to find were the new student should
*			              be added. If no such place was found (returned value is NULL)
*		                  the method returns False. Otherwise, it calls internalAdd to
*			              add the new student to the list and returns true
***************************************************************************************/
bool LecturerLinkedList::addNode(Lecturer* newLecturer) {

		Node* before = findPlace(*newLecturer);

		// check if duplicate id was found
		if (before == NULL) {
			return false;
		}

		internalAdd(*newLecturer, before); // add lecturer
		return true;
}

/***************************************************************************************
* function name: incrmntCurrent()
* The Input: None
* The output: False if end is reached, True if not
* The Function operation: If current node is list's tail, False is returned because
*			              there is no next node to move to.
*		                  If current node is not list's tail, node is incremented.
*			              If now current node is list's tail, False is returned.
*		                  Otherwise, True is returned
***************************************************************************************/
bool LecturerLinkedList::incrmntCurrent() {
	// already at list's end, return FALSE
	if (m_currentNode == m_tailDummy) {
		return false;
	}

	m_currentNode = m_currentNode->m_nextNode; // increment current node pointer to next node on list

	// reached on of list and return FALSE
	if (m_currentNode == m_tailDummy) {
		return false;
	}

	// has not reached end yet, return TRUE
	return true;
}

/***************************************************************************************
* function name: getCurrentID()
* The Input: None
* The output: Id of lecturer which current node pointer points at.
* 	          If current node points at no lecturer, ID_ERROR_VAL is returned
* The Function operation: Checks if lecturer pointer is NULL. If so, returned ID_ERROR_VAL,
*                         otherwise uses the lecturer's getID method in order to return
*                         the lecturer's id
***************************************************************************************/
int LecturerLinkedList::getCurrentID() const {
	// list is empty or reached end of list
	if (m_currentNode->m_lecturerData == NULL) {
		return ID_ERROR_VAL;
	}
	return m_currentNode->m_lecturerData->getID(); // return current lecturer's id
}

/***************************************************************************************
* function name: CurrentName()
* The Input: None
* The output: Name of lecturer which current node pointer points at.
* 	          If current node points at no lecturer, NAME_ERROR_VAL is returned
* The Function operation: Checks if lecturer pointer is NULL. If so, returned NAME_ERROR_VAL,
*                         otherwise uses the lecturer's getName method in order to return
*                         the lecturer's name
***************************************************************************************/
string LecturerLinkedList::getCurrentName() const {
	// list is empty or reached end of list
	if (m_currentNode->m_lecturerData == NULL) {
		return NAME_ERROR_VAL;
	}
	return m_currentNode->m_lecturerData->getName(); // return current lecturer's name
}

/***************************************************************************************
* function name: searchByKey(const int key)
* The Input: Id to look for
* The output: Pointer to lecturer whose id matches given value. If no such lecturer
* 	          exists, NULL is returned.
* The Function operation: Initializes a node pointer to point at list's head. Method
*			              compares given value with the id of the lecturer being
*                         pointed by current node. Scans stop once such lecturer is found
*                         or list's end is reached. If a lecturer is found, a pointer to
*                         the lecturer is returned, otherwise NULL is returned
***************************************************************************************/
Lecturer* LecturerLinkedList::searchByKey(const int key) const {

	// scan list and find the lecturer matching given key
	Node* currNode = m_headDummy->m_nextNode;
	while (currNode->m_lecturerData != NULL) {
		if (currNode->m_lecturerData->getID() == key) {
			return currNode->m_lecturerData;
		}
		currNode = currNode->m_nextNode; // move to next node
	}
	return NULL; // no match found
}

/***************************************************************************************
* function name: searchByIndex(const int index)
* The Input: Id to look for
* The output: Pointer to lecturer whose index matches given value. If no such lecturer
* 	          exists, NULL is returned.
* The Function operation: Initializes a node pointer to point at list's head. Method
*			              compares given value with the id of the lecturer being
*                         pointed by current node. Scan stop once such lecturer is found
*                         or list's end is reached. If a lecturer is found, a pointer to
*                         the lecturer is returned, otherwise NULL is returned
***************************************************************************************/
Lecturer* LecturerLinkedList::searchByIndex(const int index) const {

	// scan list and find the lecturer whose node matching given index
	Node* currNode = m_headDummy;
	while (currNode != NULL) {
		if (currNode->m_index == index) {
			return currNode->m_lecturerData;
		}
		currNode = currNode->m_nextNode; // move to next node
	}
	return NULL; // no match found
}
